package com.waimai1.waimai.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.waimai1.waimai.common.AesUtil;
import com.waimai1.waimai.common.BaseContext;
import com.waimai1.waimai.common.Utils;
import com.waimai1.waimai.config.PartnerPayConfig;
import com.waimai1.waimai.config.PayConfig;
import com.waimai1.waimai.entity.*;
import com.waimai1.waimai.exception.EnumException;
import com.waimai1.waimai.exception.NotErrorException;
import com.waimai1.waimai.service.*;
import com.wechat.pay.java.core.notification.Notification;
import com.wechat.pay.java.core.notification.Resource;
import com.wechat.pay.java.service.cashcoupons.CashCouponsService;
import com.wechat.pay.java.service.cashcoupons.model.SendCouponRequest;
import com.wechat.pay.java.service.cashcoupons.model.SendCouponResponse;
import com.wechat.pay.java.service.payments.jsapi.JsapiService;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.AmountReq;
import com.wechat.pay.java.service.refund.model.CreateRequest;
import com.wechat.pay.java.service.refund.model.Refund;
import io.netty.util.internal.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class WepayServiceImpl implements WepayService {

    //    @Value("${wxPay.appid}")
//    private String appid;
    @Value("${wxPay.mchid}")
    private String mchid;
    @Value("${wePayNotifyUrl}")
    private String notify;
    @Value("${wePayRefundNotify}")
    private String RefundNotify;
    @Autowired
    private WepayOrderService wepayOrderService;
    @Autowired
    private HwOrderService hwOrderService;
    @Autowired
    private MyOrderService orderService;
    @Autowired
    private CommissionService commissionService;
    @Autowired
    private AcidService acidService;
    public static RefundService refundService;
    public static CashCouponsService service;

    @Override
    public SendCouponResponse sendcoupon(String stockId, String openid) {
        service = new CashCouponsService.Builder().config(PayConfig.config).build();
        SendCouponRequest request = new SendCouponRequest();
        Date curDate = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyymmdd");
        String dateString = sdf.format(curDate);
        String out_request_no = mchid + dateString + openid.substring(10) + curDate.getTime();
        Acid resAcid = acidService.getById(BaseContext.getAcid());
        request.setAppid(resAcid.getAppid());
        request.setStockId(stockId);
        request.setOutRequestNo(out_request_no);
        request.setOpenid(openid);
        request.setStockCreatorMchid(mchid);
        SendCouponResponse sendCouponResponse = new SendCouponResponse();
        try {
            sendCouponResponse = service.sendCoupon(request);
        } catch (Exception e) {
            log.info(e.getMessage());
            if (e.getMessage().contains("用户已达最大领券次数")) {
                throw new NotErrorException(1201, "请勿重复领取");
            }
        }
        return sendCouponResponse;
    }

    @Override
    public PrepayResponse prepay(int totalFee, String openid, String tradeNo, String goodtag) {
        JsapiService service = new JsapiService.Builder().config(PayConfig.config).build();
        PrepayRequest request = new PrepayRequest();
        // 调用request.setXxx(val)设置所需参数，具体参数可见Request定义
        Acid resAcid = acidService.getById(BaseContext.getAcid());
        request.setAppid(resAcid.getAppid());
        request.setMchid(mchid);
        request.setDescription("蓝臣科技-付款");
        request.setOutTradeNo(tradeNo);
        request.setNotifyUrl(notify);
        Amount amount = new Amount();
        amount.setTotal(totalFee);
        amount.setCurrency("CNY");
        request.setAmount(amount);
        Payer payer = new Payer();
        payer.setOpenid(openid);
        request.setPayer(payer);
        if (!StringUtil.isNullOrEmpty(goodtag)) {
            request.setGoodsTag(goodtag);
        }
        // 调用接口
        return service.prepay(request);
    }

    /**
     * 微信支付回调
     *
     * @param request 请求
     * @return 结果
     */
    @Override
    public JSONObject getResource(HttpServletRequest request, String apiV3key) throws IOException, GeneralSecurityException {
        // TODO 必须使用request获取body（readLine读取），微信推送的消息使用@RequestBody可能一次性无法读完，造成解密失败
        String streamReadString = getRequestBody(request);
        Notification notification = JSONObject.parseObject(streamReadString, Notification.class);
        log.info("pay callback: request read={}", streamReadString);
        log.info("pay callback: request read={}", notification.toString());
        log.info("notification.getSummary() ={}", notification.getSummary());
        log.info("notification.getSummary() UTF_8 ={}", notification.getSummary().getBytes("UTF-8"));
        if ("TRANSACTION.SUCCESS".equals(notification.getEventType())) {// 中文判断会在转发中乱码，在此替换判断字段
//        if ("支付成功".equals(notification.getSummary())||"鏀\uE219粯鎴愬姛".equals(notification.getSummary())){
            Resource resource = notification.getResource();
            String associatedData = resource.getAssociatedData();
            String nonce = resource.getNonce();
            String ciphertext = resource.getCiphertext();
            byte[] associatedDataBytes = associatedData.getBytes("UTF-8");
            byte[] nonceBytes = nonce.getBytes("UTF-8");
            AesUtil aesUtil = new AesUtil(apiV3key.getBytes("utf-8"));
            String resourcedData = aesUtil.decryptToString(associatedDataBytes, nonceBytes, ciphertext);
            log.info("resourceData:" + resourcedData);
            // 解密得到的json结果
            JSONObject decryptedJsonObj = JSONObject.parseObject(resourcedData);
            return decryptedJsonObj;
        }
        return null;
    }

    /**
     * 获取请求体
     *
     * @param request 请求
     */
    private String getRequestBody(HttpServletRequest request) {
        ServletInputStream stream = null;
        BufferedReader reader = null;
        StringBuilder sb = new StringBuilder();
        try {
            stream = request.getInputStream();
            // 获取响应
            reader = new BufferedReader(new InputStreamReader(stream));
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            assert stream != null;
            try {
                stream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            assert reader != null;
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return sb.toString();
    }

    /**
     * 退款申请
     */
    /**
     * 微信支付订单号查询订单
     */
    public Transaction queryOrderById(String transactionId) {
        JsapiService jsapiService = new JsapiService.Builder().config(PayConfig.config).build();
        QueryOrderByIdRequest request = new QueryOrderByIdRequest();
        request.setTransactionId(transactionId);
        request.setMchid(mchid);
        // 调用request.setXxx(val)设置所需参数，具体参数可见Request定义
        // 调用接口
        return jsapiService.queryOrderById(request);
    }

    //全额退
    public void allRefund(MyOrder order) {
        LambdaQueryWrapper<WepayOrder> wepayOrderServiceLambdaQueryWrapper = new LambdaQueryWrapper<>();
        wepayOrderServiceLambdaQueryWrapper.eq(WepayOrder::getOutTradeNo, order.getOutTradeNo());
        WepayOrder wepayOrder = wepayOrderService.getOne(wepayOrderServiceLambdaQueryWrapper);
        if (null == wepayOrder) {
            throw new NotErrorException(EnumException.NO_WEPAY_ORDER);
        }
        Refund res = refund(wepayOrder.getSubMchid(), order.getOutTradeNo(), (long) wepayOrder.getTotal(), (long) wepayOrder.getTotal());
        if ((!("SUCCESS".equals(res.getStatus().name()))) && (!("PROCESSING".equals(res.getStatus().name())))) {

            throw new NotErrorException(1006, "退款失败" + res.getStatus());
        }
        order.setOutRefundNo(res.getOutRefundNo());
        order.setStatus(Utils.STATUS_REFUNDED);
        if (!orderService.updateById(order)) {
            throw new NotErrorException(1007, "退款异常" + res.getStatus());
        }
        ;
    }

    //    计算部分退款金额
    @Override
    public double partRefundCount(String comment, String partialRefundProduct) {
        List<Object> comments = JSON.parseArray(comment);
        List<Object> refundAll = JSON.parseArray(partialRefundProduct);
        //计算价格时有totalPrice则用totalprice，没有totalPrice则使用userPrice*count
        Double total = 0.00;
        //计算价格
        for (Object refundItem : refundAll) {
            for (Object commentItem : comments) {
                String comName = ((Map<String, Object>) commentItem).get("product_name").toString();
                String hwName = ((Map<String, Object>) refundItem).get("goodsName").toString();
                if (comName.equals(hwName)) {
                    double refundPrice = Double.parseDouble(((Map<String, Object>) refundItem).get("totalRefundAmount").toString());
                    double goodPrice = Double.parseDouble(((Map<String, Object>) refundItem).get("goodsAmount").toString());
                    double commentPrice = Double.parseDouble(((Map<String, Object>) commentItem).get("total_price").toString());
                    total = total + refundPrice * commentPrice / goodPrice;
                    break;
                }
            }
        }
        return total;
    }

    //部分退
    public void partRefund(MyOrder order) {
        order = orderService.getById(order.getId());
        if (null == order) {
            throw new NotErrorException(EnumException.NO_ORDER);
        }
        LambdaQueryWrapper<WepayOrder> wepayOrderServiceLambdaQueryWrapper = new LambdaQueryWrapper<>();
        wepayOrderServiceLambdaQueryWrapper.eq(WepayOrder::getOutTradeNo, order.getOutTradeNo());
        WepayOrder wepayOrder = wepayOrderService.getOne(wepayOrderServiceLambdaQueryWrapper);
        if (null == wepayOrder) {
            throw new NotErrorException(EnumException.NO_WEPAY_ORDER);
        }

        //计算退款金额,单位为分
        Long refundPrice = (long) partRefundCount(order.getComments(), order.getRefundInfo()) * 100;
        Refund res = refund(wepayOrder.getSubMchid(), order.getOutTradeNo(), refundPrice, (long) wepayOrder.getTotal());
        if (!("SUCCESS".equals(res.getStatus().name()))) {
            throw new NotErrorException(1006, "退款失败" + res.getStatus());
        }
        order.setOutRefundNo(res.getOutRefundNo());
        order.setRefundPrice((double)(refundPrice/100));
        order.setStatus(Utils.STATUS_REFUNDED);
        if (!orderService.updateById(order)) {
            throw new NotErrorException(1007, "退款异常" + res.getStatus());
        }
        ;
    }

    public Refund refund(String submchid, String out_trade_no, Long refundAmount, Long totalAmount) {
        refundService = new RefundService.Builder().config(PayConfig.config).build();
        if ("LS".equals(out_trade_no.substring(0, 2))) {
            refundService = new RefundService.Builder().config(PartnerPayConfig.partnerConfig).build();
        }
        // ... 调用接口
        CreateRequest request = new CreateRequest();
        if ("LS".equals(out_trade_no.substring(0, 2))) {
            request.setSubMchid(submchid);
        }
        // 调用request.setXxx(val)设置所需参数，具体参数可见Request定义
        request.setOutTradeNo(out_trade_no);
        request.setOutRefundNo("TK" + out_trade_no);
        request.setNotifyUrl(RefundNotify);
        AmountReq amountReq = new AmountReq();
        amountReq.setRefund(refundAmount);
        amountReq.setTotal(totalAmount);
        amountReq.setCurrency("CNY");
        request.setAmount(amountReq);
        // 调用接口
        return refundService.create(request);
    }

    //    @Override
//    public void closeOrder() {
//        CloseOrderRequest request = new CloseOrderRequest();
//        // 调用request.setXxx(val)设置所需参数，具体参数可见Request定义
//        // 调用接口
//        service.closeOrder(request);
//    }
//
//    @Override
//    public Transaction queryOrderById() {
//        QueryOrderByIdRequest request = new QueryOrderByIdRequest();
//        // 调用request.setXxx(val)设置所需参数，具体参数可见Request定义
//        // 调用接口
//        return service.queryOrderById(request);
//    }
//
    @Override
    public Transaction queryOrderByOutTradeNo(String OutTradeNo) {
        JsapiService service = new JsapiService.Builder().config(PayConfig.config).build();
        QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
        // 调用request.setXxx(val)设置所需参数，具体参数可见Request定义
        request.setOutTradeNo(OutTradeNo);
        request.setMchid(mchid);
        // 调用接口
        return service.queryOrderByOutTradeNo(request);
    }


}
